package com.unswift.cloud.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.unswift.annotation.api.Api;
import com.unswift.annotation.api.ApiField;
import com.unswift.annotation.api.ApiMethod;
import com.unswift.cloud.annotation.logger.OperatorLogger;
import com.unswift.cloud.core.CommonOperator;
import com.unswift.cloud.enums.OperatorTypeEnum;
import com.unswift.cloud.pojo.Pojo;
import com.unswift.cloud.pojo.mso.logger.operator.LoggerOperatorQueueMso;
import com.unswift.cloud.rabbit.RabbitConstant;
import com.unswift.cloud.rabbit.RabbitQueue;
import com.unswift.cloud.utils.LoggerUtils;
import com.unswift.utils.ClassUtils;
import com.unswift.utils.ObjectUtils;

@Aspect
@Component
@Api(value="操作日志aop", author = "unswift", date = "2023-12-10", version = "1.0.0")
public class OperatorLoggerAop extends CommonOperator implements RabbitConstant{

	private final Logger logger = LoggerFactory.getLogger(this.getClass());
	
	@Autowired
	@ApiField("Rabbit Mq发送消息服务")
	private RabbitQueue rabbitQueue;
	
	@ApiMethod("操作日志锁的切面")
	@Pointcut("@annotation(com.unswift.cloud.annotation.logger.OperatorLogger)")
	public void entryOperatorLoggerPoint() {
	}

	@ApiMethod(value="操作日志锁切面扩展", params = {@ApiField("切面的方法封装"), @ApiField("操作日志锁注解")})
	@Around("entryOperatorLoggerPoint() && @annotation(operatorLogger)")
	public Object around(ProceedingJoinPoint point, OperatorLogger operatorLogger) throws Throwable {
		LoggerOperatorQueueMso loggerMso=new LoggerOperatorQueueMso();
		try {
			Object result = point.proceed();//要等待程序执行完才能写日志
			handleLogger(point, result, operatorLogger, loggerMso);
			return result;
		} catch (Exception e) {
			handleError(point, operatorLogger, loggerMso, e);
			throw e;
		} finally {
			LoggerUtils.remove();
		}
	}
	
	@ApiMethod(value="处理-生成错误日志", params = {@ApiField("切面的方法封装"), @ApiField("操作日志锁注解"), @ApiField("日志对象"), @ApiField("异常对象")})
	private void handleError(ProceedingJoinPoint point, OperatorLogger operatorLogger, LoggerOperatorQueueMso loggerMso, Exception e) {
		String module=LoggerUtils.getModule();
		loggerMso.setModule(module);
		loggerMso.setOperatorType(operatorLogger.type().getKey());
		loggerMso.setToken(this.getHeader(tokenConfig.getKeyName()));
		if(OperatorTypeEnum.CREATE.equals(operatorLogger.type())) {
			Long id=LoggerUtils.getId();
			if(ObjectUtils.isEmpty(id)) {
				logger.error("无法获得数据id，写入日志失败");
				return ;
			}
			loggerMso.setDataId(id);
		}else {
			Object[] args=point.getArgs();
			if(ObjectUtils.isNotEmpty(args) && ObjectUtils.isNotEmpty(args[0])) {
				try {
					Long id;
					if(ObjectUtils.isNotEmpty(operatorLogger.pkFileName())) {
						id=ClassUtils.get(args[0], operatorLogger.pkFileName());
					}else {
						id=ClassUtils.get(args[0], "id");
					}
					loggerMso.setDataId(id);
				} catch (Exception e2) {
					logger.error(String.format("无法在类%s获取字段%s的值", args[0].getClass(), "id"), e);
				}
			}
		}
		loggerMso.setOperatorContent(e.getMessage());
		rabbitQueue.sendMessage(LOGGER_OPERATOR_EXCHANGE_NAME, LOGGER_OPERATOR_ROUTE_KEY, loggerMso);//发送导出队列
	}
	@ApiMethod(value="处理-生成日志", params = {@ApiField("切面的方法封装"), @ApiField("切面方法执行返回对象"), @ApiField("操作日志锁注解"), @ApiField("日志对象")})
	private void handleLogger(ProceedingJoinPoint point, Object result, OperatorLogger operatorLogger, LoggerOperatorQueueMso loggerMso) {
		try {
			String module=LoggerUtils.getModule();
			loggerMso.setModule(module);
			loggerMso.setOperatorType(operatorLogger.type().getKey());
			loggerMso.setToken(this.getHeader(tokenConfig.getKeyName()));
			if(ObjectUtils.isEmpty(module)) {
				logger.error("无法获得数据所属模块，写入日志失败");
				return ;
			}
			if(OperatorTypeEnum.CREATE.equals(operatorLogger.type())) {
				Long id=LoggerUtils.getId();
				if(ObjectUtils.isEmpty(id)) {
					logger.error("无法获得数据id，写入日志失败");
					return ;
				}
				loggerMso.setDataId(id);
				Object[] args=point.getArgs();
				if(ObjectUtils.isNotEmpty(args) && ObjectUtils.isNotEmpty(args[0])) {
					loggerMso.setOperatorContent(LoggerUtils.toLoggerString((Pojo)args[0]));
				}
			}else if(OperatorTypeEnum.UPDATE.equals(operatorLogger.type())) {
				Object[] args=point.getArgs();
				if(ObjectUtils.isEmpty(args) || ObjectUtils.isEmpty(args[0])) {
					logger.error("无法获得数据id，写入日志失败");
					return ;
				}
				Long id;
				if(ObjectUtils.isNotEmpty(operatorLogger.pkFileName())) {
					id=ClassUtils.get(args[0], operatorLogger.pkFileName());
				}else {
					id=ClassUtils.get(args[0], "id");
				}
				if(ObjectUtils.isEmpty(id)) {
					logger.error("无法获得数据id，写入日志失败");
					return ;
				}
				loggerMso.setDataId(id);
				Object originalData=LoggerUtils.getOriginalData();
				if(ObjectUtils.isNotEmpty(originalData)) {
					loggerMso.setOperatorContent(LoggerUtils.compareTo((Pojo)originalData, (Pojo)args[0]));
				}
				if(ObjectUtils.isEmpty(loggerMso.getOperatorContent())) {
					loggerMso.setOperatorContent("无变动");
				}
			}else if(OperatorTypeEnum.DELETE.equals(operatorLogger.type())) {
				Object[] args=point.getArgs();
				if(ObjectUtils.isEmpty(args) || ObjectUtils.isEmpty(args[0])) {
					logger.error("无法获得数据id，写入日志失败");
					return ;
				}
				Long id;
				if(ObjectUtils.isNotEmpty(operatorLogger.pkFileName())) {
					id=ClassUtils.get(args[0], operatorLogger.pkFileName());
				}else {
					id=ClassUtils.get(args[0], "id");
				}
				if(ObjectUtils.isEmpty(id)) {
					logger.error("无法获得数据id，写入日志失败");
					return ;
				}
				loggerMso.setDataId(id);
			}else if(OperatorTypeEnum.SEARCH.equals(operatorLogger.type()) || OperatorTypeEnum.EXPORT.equals(operatorLogger.type())) {
				Object[] args=point.getArgs();
				if(ObjectUtils.isEmpty(args) || ObjectUtils.isEmpty(args[0])) {
					logger.error("无法获得数据id，写入日志失败");
					return ;
				}
				if(ObjectUtils.isNotEmpty(args) && ObjectUtils.isNotEmpty(args[0])) {
					loggerMso.setOperatorContent(LoggerUtils.toLoggerString((Pojo)args[0]));
				}
			}
			rabbitQueue.sendMessage(LOGGER_OPERATOR_EXCHANGE_NAME, LOGGER_OPERATOR_ROUTE_KEY, loggerMso);//发送导出队列
		} catch (Exception e) {
			e.printStackTrace();
			logger.error(e.getMessage(), e);
		}
	}
}
